﻿using System;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;

namespace Oryon.Extensions.IO
{
    /// <summary>
    /// Extension Methods for IO processees
    /// </summary>
    public static class Functions
    {
        /// <summary>
        /// Compress any file with GZipStream
        /// </summary>
        /// <param name="source">Source FileInfo type</param>
        /// <returns>If accomplished it's true</returns>
        public static bool Compress(this FileInfo source)
        {
            bool result = false;
            object IOObject = new object();
            string fileName = Path.GetFileName(source.FullName);
            string zipFileName = fileName + "z";
            string targetFilePath = Path.Combine(source.Directory.FullName, zipFileName);

            using (FileStream fsTarget = new FileStream(targetFilePath, FileMode.Create))
            {
                using (GZipStream gZipStream = new GZipStream(fsTarget, CompressionMode.Compress))
                {
                    byte[] fileContent = File.ReadAllBytes(source.FullName);
                    lock (IOObject)
                    {
                        gZipStream.Write(fileContent, 0, fileContent.Length);

                    }
                    result = true;
                }
            }

            return result;
        }

        /// <summary>
        /// Dump usefull file informations into string
        /// </summary>
        /// <param name="source">FileInfo object instance</param>
        /// <returns>string content of file informations</returns>
        public static string DumpInfo(this FileInfo source)
        {
            string data = String.Empty;
            StringBuilder builder = new StringBuilder();
            Type fiType = source.GetType();
            var properties = from p in fiType.GetProperties()
                              orderby p.Name
                              select p;
            foreach (var property in properties)
            {
                builder.Append(string.Format("{0}: ", property.Name));
                builder.AppendLine(property.GetValue(source, null).ToString());
            }
            data = builder.ToString();
            return data;
        }

        /// <summary>
        /// To find total size of a Directory
        /// </summary>
        /// <param name="totalExceptionCount">Exception count for Unauthorized Access Exception Count</param>
        /// <param name="directory">Source directroy name</param>
        public static long EstimatedTotalSize(this DirectoryInfo directory,ref int totalExceptionCount)
        {
            long size = 0;

            try
            {
                foreach (var file in directory.GetFiles())
                    size += file.Length;

                foreach (var dir in directory.GetDirectories())
                    size += EstimatedTotalSize(dir, ref totalExceptionCount);

            }
            catch 
            {
                //TODO: Seperate error count into different exception set
                totalExceptionCount++;
            }

            return size;
        }

        /// <summary>
        /// Compress any folder with ZipFile 
        /// </summary>
        /// <param name="compressionLevel">Compression Level</param>
        /// <param name="destinationFileName">Destionation Zip File Name</param>
        /// <param name="includeBaseDirectory">is compression process includes base directory</param>
        /// <param name="sourceDirectory">Source folder</param>
        /// <returns>if succedded it returns true otherwise false</returns>
        public static bool CompressFolder(this DirectoryInfo sourceDirectory
            ,string destinationFileName
            ,CompressionLevel compressionLevel
            ,bool includeBaseDirectory)
        {
            bool result = false;

            try
            {
                ZipFile.CreateFromDirectory(
                    sourceDirectory.FullName
                    , destinationFileName
                    , compressionLevel
                    , includeBaseDirectory);

                result = true;
            }
            catch
            {

            }

            return result;
        }
    }
}
